/* Copyright 2010 OddRain <oddrain42@gmail.com>
 * Copyright 2010 marcus905 <marcus90@gmail.com>
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */

package com.oddrain.wifieditor;

import java.util.ArrayList;
import java.util.List;

import android.app.Activity;
import android.app.AlertDialog;
import android.app.AlertDialog.Builder;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.SharedPreferences;
import android.content.DialogInterface.OnClickListener;
import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
import android.content.pm.PackageInfo;
import android.net.wifi.WifiConfiguration;
import android.net.wifi.WifiManager;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ListView;
import android.widget.AdapterView.OnItemClickListener;

public class WifiConfigList extends Activity implements
	OnSharedPreferenceChangeListener {

    protected static final int SHOW_PREFERENCES = 0;
    private WifiManager wifi;
    private ListView wifiConfigListView;
    private List<WifiConfiguration> wifiConfigList;
    private WifiConfiguration selectedConfig;
    private WifiConfigurationAdapter aa;
    private boolean editingPrefs = false;

    private void editConfig(WifiConfiguration selectedConfig) {
        // Populate Preferences
        Context context = getApplicationContext();
        SharedPreferences prefs = PreferenceManager
        	.getDefaultSharedPreferences(context);
        prefs.registerOnSharedPreferenceChangeListener(WifiConfigList.this);
        SharedPreferences.Editor editor = prefs.edit();
        editor.clear();
    
        if (selectedConfig.SSID != null) {
            editor.putString(WifiConfigSettings.PREF_SSID,
        	    selectedConfig.SSID.replaceAll("\"", ""));
        }
    
        if (selectedConfig.BSSID != null) {
            editor.putString(WifiConfigSettings.PREF_BSSID,
        	    selectedConfig.BSSID);
        }
        editor.putBoolean(WifiConfigSettings.PREF_HIDDEN_SSID,
        	selectedConfig.hiddenSSID);
    
        editor.putBoolean(WifiConfigSettings.PREF_KEY_NONE,
        	selectedConfig.allowedKeyManagement
        		.get(WifiConfiguration.KeyMgmt.NONE));
        editor.putBoolean(WifiConfigSettings.PREF_KEY_PSK,
        	selectedConfig.allowedKeyManagement
        		.get(WifiConfiguration.KeyMgmt.WPA_PSK));
        editor.putBoolean(WifiConfigSettings.PREF_KEY_EAP,
        	selectedConfig.allowedKeyManagement
        		.get(WifiConfiguration.KeyMgmt.WPA_EAP));
        editor.putBoolean(WifiConfigSettings.PREF_KEY_IEEE,
        	selectedConfig.allowedKeyManagement
        		.get(WifiConfiguration.KeyMgmt.IEEE8021X));
    
        editor.putBoolean(WifiConfigSettings.PREF_AUTH_OPEN,
        	selectedConfig.allowedAuthAlgorithms
        		.get(WifiConfiguration.AuthAlgorithm.OPEN));
        editor.putBoolean(WifiConfigSettings.PREF_AUTH_LEAP,
        	selectedConfig.allowedAuthAlgorithms
        		.get(WifiConfiguration.AuthAlgorithm.LEAP));
        editor.putBoolean(WifiConfigSettings.PREF_AUTH_SHARED,
        	selectedConfig.allowedAuthAlgorithms
        		.get(WifiConfiguration.AuthAlgorithm.SHARED));
    
        editor.putBoolean(WifiConfigSettings.PREF_SEC_WPA,
        	selectedConfig.allowedProtocols
        		.get(WifiConfiguration.Protocol.WPA));
        editor.putBoolean(WifiConfigSettings.PREF_SEC_RSN,
        	selectedConfig.allowedProtocols
        		.get(WifiConfiguration.Protocol.RSN));
    
        editor.putBoolean(WifiConfigSettings.PREF_PAIR_NONE,
        	selectedConfig.allowedPairwiseCiphers
        		.get(WifiConfiguration.PairwiseCipher.NONE));
        editor.putBoolean(WifiConfigSettings.PREF_PAIR_CCMP,
        	selectedConfig.allowedPairwiseCiphers
        		.get(WifiConfiguration.PairwiseCipher.CCMP));
        editor.putBoolean(WifiConfigSettings.PREF_PAIR_TKIP,
        	selectedConfig.allowedPairwiseCiphers
        		.get(WifiConfiguration.PairwiseCipher.TKIP));
    
        editor.putBoolean(WifiConfigSettings.PREF_GRP_WEP40,
        	selectedConfig.allowedGroupCiphers
        		.get(WifiConfiguration.GroupCipher.WEP40));
        editor.putBoolean(WifiConfigSettings.PREF_GRP_WEP104,
        	selectedConfig.allowedGroupCiphers
        		.get(WifiConfiguration.GroupCipher.WEP104));
        editor.putBoolean(WifiConfigSettings.PREF_GRP_TKIP,
        	selectedConfig.allowedGroupCiphers
        		.get(WifiConfiguration.GroupCipher.TKIP));
        editor.putBoolean(WifiConfigSettings.PREF_GRP_CCMP,
        	selectedConfig.allowedGroupCiphers
        		.get(WifiConfiguration.GroupCipher.CCMP));
    
        if (selectedConfig.wepTxKeyIndex > 3
        	|| selectedConfig.wepTxKeyIndex < 0) {
            editor.putInt(WifiConfigSettings.PREF_WEPKEY_IDX,
        	    selectedConfig.wepTxKeyIndex);
        }
    
        if (selectedConfig.wepKeys[0] != null
        	&& selectedConfig.wepKeys[0].length() >= 2) {
            editor.putString(WifiConfigSettings.PREF_WEPKEY_KEY0,
        	    removeQuotes(selectedConfig.wepKeys[0]));
        }
    
        if (selectedConfig.wepKeys[1] != null
        	&& selectedConfig.wepKeys[1].length() >= 2) {
            editor.putString(WifiConfigSettings.PREF_WEPKEY_KEY1,
        	    removeQuotes(selectedConfig.wepKeys[1]));
        }
    
        if (selectedConfig.wepKeys[2] != null
        	&& selectedConfig.wepKeys[2].length() >= 2) {
            editor.putString(WifiConfigSettings.PREF_WEPKEY_KEY2,
        	    removeQuotes(selectedConfig.wepKeys[2]));
        }
    
        if (selectedConfig.wepKeys[3] != null
        	&& selectedConfig.wepKeys[3].length() >= 2) {
            editor.putString(WifiConfigSettings.PREF_WEPKEY_KEY3,
        	    removeQuotes(selectedConfig.wepKeys[3]));
        }
    
        if (selectedConfig.preSharedKey != null
        	&& selectedConfig.preSharedKey.length() >= 2) {
            editor.putString(WifiConfigSettings.PREF_WPA_KEY,
        	    removeQuotes(selectedConfig.preSharedKey));
        }
    
        editor.commit();
        editingPrefs = true;
    }

    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
	super.onCreate(savedInstanceState);
	setContentView(R.layout.main);

	// Setup WiFi
	wifi = (WifiManager) getSystemService(Context.WIFI_SERVICE);
	wifiConfigListView = (ListView) findViewById(R.id.wifiConfigList);

	wifiConfigListView.setOnItemClickListener(new OnItemClickListener() {
	    public void onItemClick(AdapterView<?> _av, View _v, int _index,
		    long arg3) {
		selectedConfig = wifiConfigList.get(_index);

		// Populate Preferences
		editConfig(selectedConfig);

		// Display Preferences
		Context context = getApplicationContext();
		Intent i = new Intent(context, WifiConfigSettings.class);
		i.addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY);
		startActivityForResult(i, SHOW_PREFERENCES);

	    }
	});

	wifiConfigList = new ArrayList<WifiConfiguration>();
	int resID = R.layout.wificonfiguration_item;
	aa = new WifiConfigurationAdapter(this, resID, wifiConfigList);
	wifiConfigListView.setAdapter(aa);

	Context context = getApplicationContext();
	context.registerReceiver(new BroadcastReceiver() {
	    @Override
	    public void onReceive(Context context, Intent intent) {
		loadWifiConfigs();
		System.out.println("Recieved wifi state changed action:"
			+ intent);
	    }
	}, new IntentFilter(WifiManager.WIFI_STATE_CHANGED_ACTION));

	checkWifiState();
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
	MenuInflater inflater = getMenuInflater();
	inflater.inflate(R.menu.options_menu, menu);
	return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
	Builder builder = new AlertDialog.Builder(this);
	switch (item.getItemId()) {
	case R.id.about:
	    PackageInfo pi = null;
	    try {
		pi = getPackageManager().getPackageInfo(
			getClass().getPackage().getName(), 0);
	    } catch (Exception e) {
		e.printStackTrace();
	    }
	    builder.setTitle(getString(R.string.ABOUT_TITLE));
	    builder.setMessage(getString(R.string.ABOUT_CONTENT) + "\n\n"
		    + pi.packageName + "\n" + "v" + pi.versionName + " "
		    + pi.versionCode);
	    builder.setPositiveButton(getString(android.R.string.ok), null);
	    builder.show();

	    return true;
	}
	return false;
    }

    private void loadWifiConfigs() {
	wifiConfigList.clear();
	List<WifiConfiguration> configs = wifi.getConfiguredNetworks();
	for (WifiConfiguration config : configs) {
	    wifiConfigList.add(config);
	}
	aa.notifyDataSetChanged();
    }

    private void checkWifiState() {
	boolean enabled = wifi.isWifiEnabled();
	if (!enabled) {
	    Builder builder = new AlertDialog.Builder(this);
	    builder.setTitle(getString(R.string.app_name));
	    builder.setIcon(android.R.drawable.ic_dialog_alert);
	    builder.setMessage(getString(R.string.WIFI_ENABLE_MSG));
	    builder.setPositiveButton(getString(R.string.YES),
		    new OnClickListener() {
			@Override
			public void onClick(DialogInterface dialog, int which) {
			    wifi.setWifiEnabled(true);
			}
		    });
	    builder.setNegativeButton(getString(R.string.NO), null);
	    builder.show();
	} else {
	    loadWifiConfigs();
	}
    }

    @Override
    public void onActivityResult(int requestCode, int resultCode, Intent data) {
	super.onActivityResult(requestCode, resultCode, data);
	checkWifiState();
	editingPrefs = false;
    }

    @Override
    public void onSharedPreferenceChanged(SharedPreferences sharedPreferences,
	    String key) {
	if (editingPrefs) {
	    // Save
	    saveWiFiConfig();
	}
    }

    private void saveWiFiConfig() {
	// Save Wifi Config from Preferences
	Context context = getApplicationContext();
	SharedPreferences prefs = PreferenceManager
		.getDefaultSharedPreferences(context);

	String slidingTemp = prefs
		.getString(WifiConfigSettings.PREF_SSID, null);
	if (slidingTemp != null) {
	    selectedConfig.SSID = surroundWithQuotes(slidingTemp);
	}
	slidingTemp = prefs.getString(WifiConfigSettings.PREF_BSSID, null);
	if (slidingTemp != null && slidingTemp.length() == 17
		&& // avoid regex matching if can't be a macaddr
		slidingTemp
			.matches("[0-9A-Fa-f]{2}:[0-9A-Fa-f]{2}:[0-9A-Fa-f]{2}:[0-9A-Fa-f]{2}:[0-9A-Fa-f]{2}:[0-9A-Fa-f]{2}")) {
	    selectedConfig.BSSID = slidingTemp;
	}

	if (!prefs.getBoolean(WifiConfigSettings.PREF_HIDDEN_SSID, false)) {
	    selectedConfig.hiddenSSID = false;
	} else {
	    selectedConfig.hiddenSSID = true;
	}

	selectedConfig.allowedKeyManagement.clear();
	if (prefs.getBoolean(WifiConfigSettings.PREF_KEY_IEEE, false)) {
	    selectedConfig.allowedKeyManagement
		    .set(WifiConfiguration.KeyMgmt.IEEE8021X);
	}
	if (prefs.getBoolean(WifiConfigSettings.PREF_KEY_PSK, false)) {
	    selectedConfig.allowedKeyManagement
		    .set(WifiConfiguration.KeyMgmt.WPA_PSK);
	}
	if (prefs.getBoolean(WifiConfigSettings.PREF_KEY_EAP, false)) {
	    selectedConfig.allowedKeyManagement
		    .set(WifiConfiguration.KeyMgmt.WPA_EAP);
	}
	if (prefs.getBoolean(WifiConfigSettings.PREF_KEY_NONE, false)) {
	    selectedConfig.allowedKeyManagement
		    .set(WifiConfiguration.KeyMgmt.NONE);
	}

	// GroupCiphers
	selectedConfig.allowedGroupCiphers.clear();
	if (prefs.getBoolean(WifiConfigSettings.PREF_GRP_WEP40, false)) {
	    selectedConfig.allowedGroupCiphers
		    .set(WifiConfiguration.GroupCipher.WEP40);
	}
	if (prefs.getBoolean(WifiConfigSettings.PREF_GRP_WEP104, false)) {
	    selectedConfig.allowedGroupCiphers
		    .set(WifiConfiguration.GroupCipher.WEP104);
	}
	if (prefs.getBoolean(WifiConfigSettings.PREF_GRP_CCMP, false)) {
	    selectedConfig.allowedGroupCiphers
		    .set(WifiConfiguration.GroupCipher.CCMP);
	}
	if (prefs.getBoolean(WifiConfigSettings.PREF_GRP_TKIP, false)) {
	    selectedConfig.allowedGroupCiphers
		    .set(WifiConfiguration.GroupCipher.TKIP);
	}

	// PairwiseCiphers
	selectedConfig.allowedPairwiseCiphers.clear();
	if (prefs.getBoolean(WifiConfigSettings.PREF_PAIR_TKIP, false)) {
	    selectedConfig.allowedPairwiseCiphers
		    .set(WifiConfiguration.PairwiseCipher.TKIP);
	}
	if (prefs.getBoolean(WifiConfigSettings.PREF_PAIR_CCMP, false)) {
	    selectedConfig.allowedPairwiseCiphers
		    .set(WifiConfiguration.PairwiseCipher.CCMP);
	}
	if (prefs.getBoolean(WifiConfigSettings.PREF_PAIR_NONE, false)) {
	    selectedConfig.allowedPairwiseCiphers
		    .set(WifiConfiguration.PairwiseCipher.NONE);
	}

	// Authentication Algorithms
	selectedConfig.allowedAuthAlgorithms.clear();
	if (prefs.getBoolean(WifiConfigSettings.PREF_AUTH_OPEN, false)) {
	    selectedConfig.allowedAuthAlgorithms
		    .set(WifiConfiguration.AuthAlgorithm.OPEN);
	}
	if (prefs.getBoolean(WifiConfigSettings.PREF_AUTH_SHARED, false)) {
	    selectedConfig.allowedAuthAlgorithms
		    .set(WifiConfiguration.AuthAlgorithm.SHARED);
	}
	if (prefs.getBoolean(WifiConfigSettings.PREF_AUTH_LEAP, false)) {
	    selectedConfig.allowedAuthAlgorithms
		    .set(WifiConfiguration.AuthAlgorithm.LEAP);
	}

	// Protocols
	selectedConfig.allowedProtocols.clear();
	if (prefs.getBoolean(WifiConfigSettings.PREF_SEC_RSN, false)) {
	    selectedConfig.allowedProtocols.set(WifiConfiguration.Protocol.RSN);
	}
	if (prefs.getBoolean(WifiConfigSettings.PREF_SEC_WPA, false)) {
	    selectedConfig.allowedProtocols.set(WifiConfiguration.Protocol.WPA);
	}

	// WEP Keys
	String pIdx = prefs.getString(WifiConfigSettings.PREF_WEPKEY_IDX, "-1");
	// System.err.println(pIdx);
	int idx = Integer.parseInt(pIdx);
	if (!(idx < 0 || idx > 3))
	    selectedConfig.wepTxKeyIndex = idx;

	slidingTemp = prefs
		.getString(WifiConfigSettings.PREF_WEPKEY_KEY0, null);
	if (slidingTemp != null) {
	    switch (slidingTemp.length()) {
	    case 10:
	    case 26:
	    case 58:
		if (slidingTemp.matches("[0-9A-Fa-f]*"))
		    selectedConfig.wepKeys[0] = slidingTemp;
		break;
	    default:
		selectedConfig.wepKeys[0] = surroundWithQuotes(prefs.getString(
			WifiConfigSettings.PREF_WEPKEY_KEY0, ""));
	    }
	}
	slidingTemp = prefs
		.getString(WifiConfigSettings.PREF_WEPKEY_KEY1, null);
	if (slidingTemp != null) {
	    switch (slidingTemp.length()) {
	    case 10:
	    case 26:
	    case 58:
		if (slidingTemp.matches("[0-9A-Fa-f]*"))
		    selectedConfig.wepKeys[1] = slidingTemp;
		break;
	    default:
		selectedConfig.wepKeys[1] = surroundWithQuotes(prefs.getString(
			WifiConfigSettings.PREF_WEPKEY_KEY1, ""));
	    }
	}
	slidingTemp = prefs
		.getString(WifiConfigSettings.PREF_WEPKEY_KEY2, null);
	if (slidingTemp != null) {
	    switch (slidingTemp.length()) {
	    case 10:
	    case 26:
	    case 58:
		if (slidingTemp.matches("[0-9A-Fa-f]*"))
		    selectedConfig.wepKeys[2] = slidingTemp;
		break;
	    default:
		selectedConfig.wepKeys[2] = surroundWithQuotes(prefs.getString(
			WifiConfigSettings.PREF_WEPKEY_KEY2, ""));
	    }
	}
	slidingTemp = prefs
		.getString(WifiConfigSettings.PREF_WEPKEY_KEY3, null);
	if (slidingTemp != null) {
	    switch (slidingTemp.length()) {
	    case 10:
	    case 26:
	    case 58:
		if (slidingTemp.matches("[0-9A-Fa-f]*"))
		    selectedConfig.wepKeys[3] = slidingTemp;
		break;
	    default:
		selectedConfig.wepKeys[3] = surroundWithQuotes(prefs.getString(
			WifiConfigSettings.PREF_WEPKEY_KEY3, ""));
	    }
	}

	slidingTemp = prefs.getString(WifiConfigSettings.PREF_WPA_KEY, null);
	if (slidingTemp != null) {
	    if (slidingTemp.matches("[0-9A-Fa-f]{64}"))
		selectedConfig.preSharedKey = slidingTemp;
	    else
		selectedConfig.preSharedKey = surroundWithQuotes(slidingTemp);
	}

	wifi.updateNetwork(selectedConfig);
	wifi.enableNetwork(selectedConfig.networkId, false);
	wifi.saveConfiguration();
    }

    static String removeQuotes(String str) {
	int len = str.length();
	if ((len > 1) && (str.charAt(0) == '"') && (str.charAt(len - 1) == '"')) {
	    return str.substring(1, len - 1);
	}
	return str;
    }

    static String surroundWithQuotes(String string) {
	return "\"" + string + "\"";
    }
}